<?php

class Artist extends DBObject {

    public $table = 'mtl.artists';
    const table_static = 'mtl.artists';
    public $sequence = 'mtl.artists_id';
    const sequence_static = 'mtl.artists_id';

    public $_old_name;
    public $_year_formed;
    public $_year_disbanded;
    public $_myspace;
    public $_homepage;
    public $_country;
    public $_has_picture;
    public $_signed;
    public $_picture_path;

    public $_current_label; // readonly
    public $_wiki; // readonly
    public $_genre; // readonly
    public $_latest_album; // readonly
    public $_latest_album_year; // readonly

    public static function getById($id) {

        return parent::getById($id, __CLASS__);
    }

    public static function getByName($name) {

        return parent::getByName($name, __CLASS__);
    }

    public function load() {

        parent::load();
        
        $res = $this->dbo->getRow("SELECT
            name,
            old_name,
            year_formed,
            year_disbanded,
            myspace,
            homepage,
            country,
            has_picture,
            signed,
            picture_path,
            (SELECT mtl.get_label_name_by_id(artists_rel_label.label_id) AS get_label_name_by_id
                       FROM mtl.artists_rel_label
                      WHERE artists_rel_label.artist_id = artists.id
                      ORDER BY artists_rel_label.year DESC
                     LIMIT 1) AS current_label,
             (SELECT mtl.get_tag_name_by_id(artists_rel_tag.tag_id) AS get_tag_name_by_id
                       FROM mtl.artists_rel_tag
                      WHERE artists_rel_tag.artist_id = artists.id
                      ORDER BY artists_rel_tag.power DESC
                     LIMIT 1) AS genre,
            (SELECT mtl.get_release_name_by_id(artists_rel_release.release_id) AS get_release_name_by_id
                       FROM mtl.artists_rel_release
                      WHERE artists_rel_release.artist_id = artists.id AND NOT mtl.is_scheduled_release(artists_rel_release.release_id)
                      ORDER BY mtl.get_release_year_by_id(artists_rel_release.release_id) DESC
                     LIMIT 1) AS latest_album,
            (SELECT mtl.get_release_year_by_id(artists_rel_release.release_id) AS get_release_year_by_id
                       FROM mtl.artists_rel_release
                      WHERE artists_rel_release.artist_id = artists.id AND NOT mtl.is_scheduled_release(artists_rel_release.release_id)
                      ORDER BY mtl.get_release_year_by_id(artists_rel_release.release_id) DESC
                     LIMIT 1) AS latest_album_year
            FROM $this->table
            WHERE id=?",
            array(
                DBInteger::create($this->id)
            ),
            DB_FETCHMODE_ASSOC
        );

        throwOnError($res);

        if(empty($res))
            throw new Exception(_('Failed to load artist.'));

        $this->name = DBString::create($res['name']);
        $this->old_name = DBString::create($res['old_name']);
        $this->year_formed = DBYear::create($res['year_formed']);
        $this->year_disbanded = DBYear::create($res['year_disbanded']);
        $this->myspace = DBUrl::create($res['myspace']);
        $this->homepage = DBUrl::create($res['homepage']);
        $this->country = DBString::create($res['country']);
        $this->has_picture = DBBoolean::create($res['has_picture']);
        $this->signed = DBBoolean::create($res['signed']);
        $this->picture_path = DBString::create($res['picture_path']);
        
        $this->current_label = DBString::create($res['current_label']);
        $this->genre = DBString::create($res['genre']);
        $this->latest_album = DBString::create($res['latest_album']);
        $this->latest_album_year = DBString::create($res['latest_album_year']);

        return true;
    }

    public function loadByName() {

        parent::loadByName();

        $res = $this->dbo->getRow("SELECT
            id,
            old_name,
            year_formed,
            year_disbanded,
            myspace,
            homepage,
            country,
            has_picture,
            signed,
            picture_path,
            (SELECT mtl.get_label_name_by_id(artists_rel_label.label_id) AS get_label_name_by_id
                       FROM mtl.artists_rel_label
                      WHERE artists_rel_label.artist_id = artists.id
                      ORDER BY artists_rel_label.year DESC
                     LIMIT 1) AS current_label,
             (SELECT mtl.get_tag_name_by_id(artists_rel_tag.tag_id) AS get_tag_name_by_id
                       FROM mtl.artists_rel_tag
                      WHERE artists_rel_tag.artist_id = artists.id
                      ORDER BY artists_rel_tag.power DESC
                     LIMIT 1) AS genre,
            (SELECT mtl.get_release_name_by_id(artists_rel_release.release_id) AS get_release_name_by_id
                       FROM mtl.artists_rel_release
                      WHERE artists_rel_release.artist_id = artists.id AND NOT mtl.is_scheduled_release(artists_rel_release.release_id)
                      ORDER BY mtl.get_release_year_by_id(artists_rel_release.release_id) DESC
                     LIMIT 1) AS latest_album,
            (SELECT mtl.get_release_year_by_id(artists_rel_release.release_id) AS get_release_year_by_id
                       FROM mtl.artists_rel_release
                      WHERE artists_rel_release.artist_id = artists.id AND NOT mtl.is_scheduled_release(artists_rel_release.release_id)
                      ORDER BY mtl.get_release_year_by_id(artists_rel_release.release_id) DESC
                     LIMIT 1) AS latest_album_year
            FROM $this->table
            WHERE LOWER(name)=LOWER(?)",
            array(
                DBString::create($this->name)
            ),
            DB_FETCHMODE_ASSOC
        );

        throwOnError($res);

        if(empty($res))
            throw new Exception(_('Failed to load artist.'));

        $this->id = DBInteger::create($res['id']);
        $this->old_name = DBString::create($res['old_name']);
        $this->year_formed = DBYear::create($res['year_formed']);
        $this->year_disbanded = DBYear::create($res['year_disbanded']);
        $this->myspace = DBUrl::create($res['myspace']);
        $this->homepage = DBUrl::create($res['homepage']);
        $this->country = DBString::create($res['country']);
        $this->has_picture = DBBoolean::create($res['has_picture']);
        $this->signed = DBBoolean::create($res['signed']);
        $this->picture_path = DBString::create($res['picture_path']);

        $this->current_label = DBString::create($res['current_label']);
        $this->genre = DBString::create($res['genre']);
        $this->latest_album = DBString::create($res['latest_album']);
        $this->latest_album_year = DBString::create($res['latest_album_year']);

        return true;
    }

    public function __set($name, $value) {

        $value = trim($value);

        // validation goes here
        switch($name) {
            case 'name':
            case 'old_name':
                if(strlen($value) > MAX_ARTIST_NAME_LENGTH)
                    throw new Exception(_('Artist name can be ').MAX_ARTIST_NAME_LENGTH._(' characters max.'));

                if($name == 'name' && strlen($value) == 0)
                    throw new Exception(_('Artist name must not be empty.'));

                break;

            case 'year_formed':
            case 'year_disbanded':
                if(strlen($value) > 0 && !preg_match('/^[0-9]{4}$/', $value))
                    throw new Exception(_('Invalid year format: ') . $value);

                break;

            case 'myspace':
            case 'homepage':
                if(strlen($value) > 0)
                    if(!filter_var($value, FILTER_VALIDATE_URL))
                        throw new Exception(_('Invalid url: ') . $value);

                if(strlen($value) > MAX_ARTIST_URL_LENGTH)
                    throw new Exception(_('URL can be ').MAX_ARTIST_URL_LENGTH._(' characters max.'));

                break;

            case 'country':
                if(strlen($value) > MAX_ARTIST_COUNTRY_LENGTH)
                    throw new Exception(_('Country can be ').MAX_ARTIST_COUNTRY_LENGTH._(' characters max.'));

                if(strlen($value) > 0 && !preg_match('/^[a-zA-Z\s]+$/', $value))
                    throw new Exception(_('Country: invalid characters.'));
                    
                break;
        }

        parent::__set($name, $value);
    }

    public function __get($name) {

        return parent::__get($name);
    }

    public function save() {

        //if(!$this->changed && $this->loaded)
        //    return true;

        if(!is_null($this->id)) {

            $res = $this->dbo->query("UPDATE $this->table SET
                name=?,
                old_name=?,
                year_formed=?,
                year_disbanded=?,
                myspace=?,
                homepage=?,
                country=?,
                has_picture=?,
                signed=?,
                picture_path=?
                WHERE id=?",
                array(
                    DBString::create($this->name),
                    DBString::create($this->old_name),
                    DBYear::create($this->year_formed),
                    DBYear::create($this->year_disbanded),
                    DBUrl::create($this->myspace),
                    DBUrl::create($this->homepage),
                    DBString::create($this->country),
                    DBBoolean::create($this->has_picture),
                    DBBoolean::create($this->signed),
                    DBString::create($this->picture_path),
                    DBInteger::create($this->id)
                ));

            throwOnError($res);

            if($res != DB_OK)
                throw new Exception(_('Failed to save artist.'));

        } else {

           parent::save(__CLASS__);
           //$this->changed = true;
           $this->save();

        }

        return $this->id;
    }

    public function isWatchedByUser($user_id) {

        $res = $this->dbo->getOne("SELECT COUNT(*)
            FROM mtl.watch_artists
            WHERE user_id = ? AND artist_id=?",
            array(
                DBInteger::create($user_id),
                DBInteger::create($this->id)
            ),
            DB_FETCHMODE_ASSOC);

        throwOnError($res);

        return ($res > 0);
    }

    public function uploadPicture($file) {

        $picture_path = $this->name . " " . $this->id;
        $picture_path = str_replace(" ", "_", $picture_path);
        $picture_path = ereg_replace("[^A-Za-z0-9\_]", "", $picture_path);

        $db_path = '/'.ARTISTS_THUMB_DIR . $picture_path;

        $picture_path = $_SERVER['DOCUMENT_ROOT'] . ARTISTS_THUMB_DIR . $picture_path;

        $result_path = Picture::upload($file, $picture_path);

        Picture::generateThumbnail($result_path, ARTISTS_THUMB_WIDTH, ARTISTS_THUMB_HEIGHT);

        $this->picture_path = $db_path . '.' . end(explode('.', $result_path));

        $this->save();

        return true;
    }

    public function uploadPictureFromUrl($url) {

        $picture_path = $this->name . " " . $this->id;
        $picture_path = str_replace(" ", "_", $picture_path);
        $picture_path = ereg_replace("[^A-Za-z0-9\_]", "", $picture_path);

        $db_path = '/'.ARTISTS_THUMB_DIR . $picture_path;

        $picture_path = $_SERVER['DOCUMENT_ROOT'] . ARTISTS_THUMB_DIR . $picture_path;

        $result_path = Picture::uploadFromUrl($url, $picture_path);

        Picture::generateThumbnail($result_path, ARTISTS_THUMB_WIDTH, ARTISTS_THUMB_HEIGHT);

        $this->picture_path = $db_path . '.' . end(explode('.', $result_path));

        $this->save();

        return true;
    }

    public function getComments() {

        $res = $this->dbo->getAll("SELECT
            com.id,
            date_trunc('second', com.date_added) as date_added,
            u.name as user_name,
            com.added_by_user_id as user_id,
            u.picture_path,
            com.message
         FROM mtl.artists_comments com
         LEFT JOIN sys.users u ON (u.id = com.added_by_user_id)
         WHERE com.artist_id = ?
         ORDER BY com.id DESC",
        array(
            DBInteger::create($this->id)
        ),
        DB_FETCHMODE_ASSOC);

        throwOnError($res);

        return $res;
    }

    public function getReleases() {

        $res = $this->dbo->getAll("SELECT 
                rel.release_id as id,
                r.year_finished,
                r.schedule_date,
                r.name
            FROM mtl.artists_rel_release rel
            LEFT JOIN mtl.releases r ON (r.id = rel.release_id)
            WHERE rel.artist_id=?
            ORDER BY year_finished ASC, schedule_date DESC",
            array(
                DBInteger::create($this->id)
            ),
        DB_FETCHMODE_ASSOC);

        throwOnError($res);

        return $res;
    }

    public function getMembers() {

        $res = $this->dbo->getAll("SELECT
                rel.member_id as id,
                rel.year_started,
                rel.year_finished,
                m.name
            FROM mtl.artists_rel_member rel
            LEFT JOIN mtl.members m ON (m.id = rel.member_id)
            WHERE rel.artist_id=?
            ORDER BY rel.year_started ASC",
            array(
                DBInteger::create($this->id)
        ),
        DB_FETCHMODE_ASSOC);

        throwOnError($res);

        return $res;
    }

    public function getLabels() {

        $res = $this->dbo->getAll("SELECT rel.label_id as id, rel.year, l.name
            FROM mtl.artists_rel_label rel
            LEFT JOIN mtl.labels l ON (l.id = rel.label_id)
            WHERE rel.artist_id=?
            ORDER BY rel.year ASC",
            array(
                DBInteger::create($this->id)
        ),
        DB_FETCHMODE_ASSOC);

        throwOnError($res);

        return $res;
    }

    public function getTags($count = 5) {

        $res = $this->dbo->getAll("SELECT rel.tag_id as id, t.name
            FROM mtl.artists_rel_tag rel
            LEFT JOIN mtl.tags t ON (t.id = rel.tag_id)
            WHERE rel.artist_id=? ORDER BY rel.power DESC LIMIT ?",
            array(
                DBInteger::create($this->id),
                DBInteger::create($count)
        ),
        DB_FETCHMODE_ASSOC);

        throwOnError($res);

        return $res;
    }

    public function linkWithTag($name) {

        if(!Tag::exists($name))
            $tag = Tag::create($name);
        else
            $tag = Tag::getByName($name);

        $res = $this->dbo->query("SELECT mtl.link_artist_with_tag(?,?)",
            array(
                DBInteger::create($this->id),
                DBInteger::create($tag->id)
                ));

        throwOnError($res);

        return true;
    }

    public function linkedWithTag($name) {

        if(!Tag::exists($name))
            return false;

        $tag = Tag::getByName($name);

        $res = $this->dbo->getOne("SELECT COUNT(*)
            FROM mtl.artists_rel_tag
            WHERE artist_id = ? AND tag_id = ?",
            array(
                DBInteger::create($this->id),
                DBInteger::create($tag->id)
            ));

        throwOnError($res);

        return ($res > 0);
    }

    public function linkWithLabel($name, $year) {
        if(!Label::exists($name))
            $label = Label::create($name);
        else
            $label = Label::getByName($name);

        $res = $this->dbo->query("SELECT mtl.link_artist_with_label(?,?,?)",
            array(
                DBInteger::create($this->id),
                DBInteger::create($label->id),
                DBYear::create($year)
            ));

        throwOnError($res);

        return true;
    }

    public function linkedWithLabel($name, $year) {

        if(!Label::exists($name))
            return false;

        $label = Label::getByName($name);

        $res = $this->dbo->getOne("SELECT COUNT(*)
            FROM mtl.artists_rel_label
            WHERE artist_id = ? AND label_id = ? AND year = ?",
            array(
                DBInteger::create($this->id),
                DBInteger::create($label->id),
                DBYear::create($year)
            ));

        throwOnError($res);

        return ($res > 0);
    }

    public function linkWithRelease($id) {

        $res = $this->dbo->query("SELECT mtl.link_artist_with_release(?,?)",
            array(
                DBInteger::create($this->id),
                DBInteger::create($id)
            ));

        throwOnError($res);

        return true;
    }

    public function linkedWithRelease($name, $year) {

        if(!Release::exists($name, $year))
            return false;

        //$release = Release::getByName($name, $year);

        $res = $this->dbo->getOne("SELECT COUNT(*)
            FROM mtl.artists_rel_release rel
            LEFT JOIN mtl.releases r ON (rel.release_id = r.id)
            WHERE rel.artist_id = ? AND r.year_finished = ? AND LOWER(r.name) = LOWER(?)",
            array(
                DBInteger::create($this->id),
                DBYear::create($year),
                DBString::create($name)
            ));

        throwOnError($res);

        return ($res > 0);
    }

    public function linkWithMember($name, $year_started, $year_finished) {

        if(!Member::exists($name))
            $member = Member::create($name);
        else
            $member = Member::getByName($name);

        $res = $this->dbo->query("SELECT mtl.link_artist_with_member(?,?,?,?)",
            array(
                DBInteger::create($this->id),
                DBInteger::create($member->id),
                DBYear::create($year_started),
                DBYear::create($year_finished)
                ));

        throwOnError($res);

        return true;
    }

    public function linkedWithMember($name, $year_started, $year_finished) {

        if(!Member::exists($name))
            return false;

        $member = Member::getByName($name);

        $res = $this->dbo->getOne("SELECT COUNT(*)
            FROM mtl.artists_rel_member
            WHERE artist_id = ? AND member_id = ? AND year_started = ? AND year_finished = ?",
            array(
                DBInteger::create($this->id),
                DBInteger::create($member->id),
                DBYear::create($year_started),
                DBYear::create($year_finished)
            ));

        throwOnError($res);

        return ($res > 0);
    }

    public function addComment($message, $user_id) {

        $res = $this->dbo->query("SELECT mtl.add_artist_comment(?,?,?,?)",
            array(
                DBInteger::create($this->id),
                DBInteger::create($user_id),
                DBComment::create($message),
                DBString::create($_SERVER['REMOTE_ADDR'])
            ));

        throwOnError($res);

        return true;
    }

    public function hasUpcomingRelease($release_name = null) {

        $res = $this->dbo->getOne("SELECT id
            FROM mtl.schedules_view
            WHERE LOWER(artist_name) = LOWER(?)",
            array(
                DBString::create($this->name)
            ));
        
        throwOnError($res);

        if(empty($res)) {

            $res = $this->dbo->getOne('SELECT id FROM mtl.releases_view
                WHERE year_finished = ? AND
                      LOWER(name) = LOWER(?)
                      AND LOWER(artist_name) = LOWER(?)',
                array(
                    DBYear::create(date('Y')),
                    DBString::create($release_name),
                    DBString::create($this->name)
                ));

            throwOnError($res);
        }

        return ($res);
    }

    public static function create($name) {

        return parent::create($name, __CLASS__);
    }

    public static function exists($name) {

        return parent::exists($name, __CLASS__);
    }

}